package org.smile.resource;

import java.io.IOException;
import java.util.*;
import java.util.ResourceBundle.Control;
import java.util.concurrent.ConcurrentHashMap;

import net.sf.cglib.core.Local;
import org.smile.Smile;
import org.smile.collection.JoinEnumeration;
import org.smile.collection.MapUtils;
import org.smile.commons.SmileRunException;
import org.smile.commons.Strings;
import org.smile.log.LoggerHandler;
/***
 * 资源管理器
 * @author 胡真山
 *
 */
public class MessageResource implements I18n,LoggerHandler{
	/**默认的语言环境*/
	protected static Locale ROOT_LOCALE;

	protected final static ResourceBundle EMPTY=new ResourceBundle() {
		public Enumeration<String> getKeys() { return null; }
		protected Object handleGetObject(String key) { return null; }
		public String toString() { return "EMPTY"; }
	};;
	
	static{
		//从配置文件读取默认
		try {
			ROOT_LOCALE = Smile.config.getValue(Smile.I18N_DEFAULT_LOCAL_KEY, Locale.class);
		} catch (SmileRunException e) {
			logger.warn("Invalid resource local config in "+Smile.I18N_DEFAULT_LOCAL_KEY, e);
		}
		if(ROOT_LOCALE==null){ //没有配置是使用语言环境
			ROOT_LOCALE=Locale.ROOT;
		}
	}
	/***
	 * 资源文件文件名
	 */
	protected String resourceName=Smile.MESSAGE_RESOURCES_NAME;
	/***
	 * 默认的资源文件
	 */
	private ResourceBundle defaultBundle;
	/**
	 * 缓存所有的资源文件
	 */
	private Map<Locale,ResourceBundle> bundleCache=new ConcurrentHashMap<Locale,ResourceBundle>();
	/**
	 * 默认方言
	 */
	private Locale defaultLocale=ROOT_LOCALE;
	/**使用Map扩展信息*/
	private Map<String,Map<String,Object>> extendsMessages=null;
	
	public MessageResource(String resourceName){
		this.resourceName=resourceName;
		initDefault();
	}

	public MessageResource(String resourceName,Map<String,Map<String,Object>> extendsMessages){
		this.resourceName=resourceName;
		this.extendsMessages=extendsMessages;
	}
	
	public MessageResource(String resourceName,Locale defaultLocal){
		this.resourceName=resourceName;
		this.defaultLocale=defaultLocal;
		initDefault();
	}
	
	public MessageResource(){
		initDefault();
	}
	/**
	 * 初始化默认设置 
	 */
	private void initDefault(){
		ResourceBundle bundle=getResourceBundle(defaultLocale);
		//系统默认方言
		ResourceBundle defaultLoad=getResourceBundle(Locale.getDefault());
		if(defaultLoad!=null){
			bundleCache.put(Locale.getDefault(), defaultLoad);
		}
		if(bundle!=null){
			defaultBundle=bundle;
		}else{
			defaultBundle=defaultLoad;
		}
	}
	
	/**如果不存在以key为默认返回*/
	public String getStringKeyDefault(Locale locale,String key){
		return getString(locale, key, true);
	}
	
	/**如果不存在以key为默认返回*/
	public String getString(Locale locale,String key){
		return getString(locale, key, false);
	}
	
	public String getString(Locale locale,String key,boolean keyDefault){
		ResourceBundle bundle=getResourceBundle(locale);
		try{
			if(bundle!=null&&bundle!=EMPTY){
				return bundle.getString(key);
			}
			//还没有使用默认的
			if(defaultBundle!=null){
				return defaultBundle.getString(key);
			}
		}catch(MissingResourceException e){
			onMessingResource(e);
		}
		return keyDefault?key:null;
	}
	
	public String getDefaultString(String key){
		return defaultBundle.getString(key);
	}
	/**
	 * 默认的资源
	 * @param locale
	 * @return
	 */
	public ResourceBundle  getResourceBundle(Locale locale){
		ResourceBundle bundle= bundleCache.get(locale);
		if(bundle==null){
			final Locale realLocal=locale;
			try{
				bundle=ResourceBundle.getBundle(resourceName, locale,new Control(){
					@Override
					public List<Locale> getCandidateLocales(String baseName, Locale local) {
						List<Locale>  list=super.getCandidateLocales(baseName, local);
						List<Locale> result=new LinkedList<Locale>();
						for(Locale l:list){
							if(Strings.BLANK.equals(l.getLanguage())){
								if(!Strings.BLANK.equals(defaultLocale.getLanguage())) {
									result.add(defaultLocale);
								}
							}else if(l.getLanguage().equals(realLocal.getLanguage())){
								result.add(l);
							}
						}
						return result;
					}

					@Override
					public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
						ResourceBundle resourceBundle=super.newBundle(baseName, locale, format, loader, reload);
                        return buildResourceBundle(resourceBundle,locale);
                    }

					@Override
					public List<String> getFormats(String baseName) {
						return Control.FORMAT_PROPERTIES;
					}
				});
				bundleCache.put(locale, bundle);
			}catch(MissingResourceException e){
				onMessingResource(e);
				ResourceBundle resourceBundle=EMPTY;
				bundleCache.put(locale,buildResourceBundle(resourceBundle,locale));
			}
		}
		return bundle;
	}

	protected  ResourceBundle buildResourceBundle(ResourceBundle resourceBundle,Locale locale){
		if (resourceBundle!=null&&extendsMessages != null) {
			Map<String, Object> mapMessage = getMapMessage(locale);
			if (MapUtils.notEmpty(mapMessage)) {
				return new MapExtendResourceBundle(resourceBundle, mapMessage);
			}
		}
		return resourceBundle;
	}

	protected Map<String,Object> getMapMessage(Locale locale){
		if(MapUtils.isEmpty(extendsMessages)){
			return null;
		}
		String localName=locale.toString();
		Map<String,Object> map=extendsMessages.get(localName);
		if(map==null){
			map=extendsMessages.get(getLocalStandby(localName));
		}
		return map;
	}


	protected final String getLocalStandby(String localName) {
		if (localName == null) {
			return "zh";
		} else {
			return org.smile.util.StringUtils.splitc(localName, new char[]{'-','_'})[0];
		}
	}

	private  void onMessingResource(MissingResourceException e){
		logger.error(e.getMessage());
	}
	
	public static Locale getRootLocale(){
		return ROOT_LOCALE;
	}

	@Override
	public String getText(String key) {
		return this.getDefaultString(key);
	}

	@Override
	public String getText(Locale locale, String key) {
		return this.getStringKeyDefault(locale,key);
	}

	public String getResourceName() {
		return resourceName;
	}

	class MapExtendResourceBundle extends ResourceBundle{
		Map<String,Object> extendsMap=new HashMap();

		MapExtendResourceBundle(ResourceBundle parent,Map<String,Object> extendsMap){
			this.setParent(parent);
			this.extendsMap.putAll(extendsMap);
		}

		@Override
		protected Object handleGetObject(String key) {
			Object obj=extendsMap.get(key);
			return obj;
		}

		@Override
		public Enumeration<String> getKeys() {
			if(MapUtils.isEmpty(extendsMap)){
				return parent.getKeys();
			}else{
				return new JoinEnumeration(extendsMap.keySet(),parent==null?null:parent.getKeys());
			}
		}
	}
}
